#include <isr.h>
#include <pic.h>
#include <idt.h>
#include <debug.h>

#include <vga.h>

/* Arreglo de rutinas de atencion de excepciones e interrupciones */

isr_ptr isrs[ISR_LENGTH] = {NULL};

static void isr_default_isr(uint_32 index, uint_32 error_code, task_state *st);
static void isr_gp_isr(uint_32 index, uint_32 error_code, task_state *st);
static void isr_pf_isr(uint_32 index, uint_32 error_code, task_state *st);
static void isr_tt_isr(uint_32 index, uint_32 error_code, task_state *st);
static void isr_kb_isr(uint_32 index, uint_32 error_code, task_state *st);
static void isr_sc_isr(uint_32 index, uint_32 error_code, task_state *st);

/**
 * Inicializa los elementos del arreglo de rutinas de atencion 
 * de interrupcion.
 * 
 */ 
 
void isr_init()
{
	isr_register(IDT_INDEX_GENERALPROT, isr_gp_isr);
	isr_register(IDT_INDEX_PAGEFAULT, isr_pf_isr);
	isr_register(IDT_INDEX_TIMERTICK, isr_tt_isr);
	isr_register(IDT_INDEX_KEYBOARD, isr_kb_isr);
	isr_register(IDT_INDEX_SYSCALL, isr_sc_isr);
}

/**
 * Handler principal para todas las excepciones.
 * 
 * Cada vez que se produce una excepcion se ejecuta esta funcion, 
 * la cual ejecuta el handler correspondiente.
 * 
 * @param index			Numero de interrupcion.
 * @param error_code	Codigo de error.
 * @param st			Puntero al estado del proceso interrupido.
 * 
 */
 
void isr_handler(uint_32 index, uint_32 error_code, task_state *st)
{
    if(isrs[index] == NULL)
        isr_default_isr(index, error_code, st);

    else
        isrs[index](index, error_code, st);
}

/**
 * Handler principal para todas las interrupciones.
 * 
 * Cada vez que se produce una interrupcion se ejecuta esta funcion, 
 * la cual ejecuta el handler correspondiente.
 * 
 * @param index			Numero de interrupcion.
 * @param error_code	Codigo de error.
 * @param st			Puntero al estado del proceso interrupido.
 * 
 */

void irq_handler(uint_32 index, uint_32 error_code, task_state *st)
{
	pic_eoi_1();

    if(isrs[index] == NULL)
		isr_default_isr(index, error_code, st);
		
    else
		isrs[index](index, error_code, st);
}

/**
 * Registra una nueva interrupt service routine para la interrupcion indicada.
 * 
 * @param index		Numero de interrupcion a registrar.
 * @param isr		Handler a registrar.
 *
 * @return			Si index no es un valor valido, devuelve ISR_BAD_INDEX.
 * 					Si index ya tiene un handler asociado, devuelve ISR_INDEX_IN_USE.
 * 					Caso contrario, devuelve ISR_OK.
 */
 
uint_32 isr_register(uint_32 index, isr_ptr isr)
{
    // Veo si el indice es valido
    
    if ((index < 0) || (index > ISR_LENGTH - 1))
        return ISR_BAD_INDEX;

    // Veo si la interrupcion ya esta siendo atendida
    
    if (isrs[index] != NULL)
        return ISR_INDEX_IN_USE;

    isrs[index] = isr;

    return ISR_OK;
}

/* Interrupt Service Routine's */

static void isr_default_isr(uint_32 index, uint_32 error_code, task_state *st)
{
	debug_kernelpanic(index, error_code, st);
}

/* General Protection */

static void isr_gp_isr(uint_32 index, uint_32 error_code, task_state *st)
{
	debug_kernelpanic(index, error_code, st);
}

/* Page Fault */

static void isr_pf_isr(uint_32 index, uint_32 error_code, task_state *st)
{
	debug_kernelpanic(index, error_code, st);
}

/* Timer Tick */

static void isr_tt_isr(uint_32 index, uint_32 error_code, task_state *st)
{
	debug_kernelpanic(index, error_code, st);
}

/* Keyboard */

static void isr_kb_isr(uint_32 index, uint_32 error_code, task_state *st)
{
	debug_kernelpanic(index, error_code, st);
}

/* Syscall */

static void isr_sc_isr(uint_32 index, uint_32 error_code, task_state *st)
{
	debug_kernelpanic(index, error_code, st);
}
